#include "NTdict.h"

unsigned int NTdict_hash_key(char *data, unsigned long len)
{
    unsigned int  i, key;
	
    key = 0;
	
    for (i = 0; i < len; i++) {
        key = NTdict_hash(key, data[i]);
    }
	
    return key;
}

int NTdict_init(NTdict_t **dict)
{
	NTdict_t *p;
	p=(NTdict_t *)malloc(NTdict_PAGE_SIZE);
	if(p == NULL)
		return -1;

	p->pages = 1;
	p->last = p->first;
	p->first->items = 0;
	p->first->available = NTdict_PAGE_SIZE - offsetof(NTdict_t,first) - offsetof(NTdict_page_t,d);
	p->first->next = NULL;
	p->first->end = p->first->d;
	*dict = p;
	//printf("page 1 NET.size %d\n",p->first->available);
	return NTdict_OK;
}

int NTdict_append(NTdict_t *dict,char *key,char *value,unsigned int valueSize)
{
	NTdict_page_t *page;
	NTdict_data_t *local;
	unsigned int klen,ksize,vsize,size;

	klen = strlen(key) + 1;
	if(klen <= 1)
		return NTdict_ERROR;
	ksize = NTdict_align(klen, sizeof(void *));
	if(ksize > NTdict_MAX_KEY_SIZE)
		return NTdict_ERROR;
	vsize = NTdict_align(valueSize, sizeof(void *));
	vsize = ksize + vsize > NTdict_LARGE_KV_SIZE ? 0 : vsize;
	size = offsetof(NTdict_data_t,key) + ksize + vsize;
 	
TRY_AGAIN_SEG:	
	page = dict->last;
	local = (NTdict_data_t *)page->end;

	if(size > page->available){
		
		page->next = (NTdict_page_t *)malloc(NTdict_PAGE_SIZE);
		if(page->next == NULL)
			return NTdict_ERROR;
		
		dict->last = page->next;
		dict->pages += 1;

		page = page->next;
		page->items = 0;
		page->available = NTdict_PAGE_SIZE - offsetof(NTdict_page_t,d);
		page->end = page->d;
		page->next = NULL;
		//printf("OVER FLOW %d > %d ,new page %p NET.size %d\n",size , page->available,page,page->available);
		goto TRY_AGAIN_SEG;
	}
	local->hash = NTdict_hash_key(key,klen);
	local->klen = klen;
	local->ksize = ksize;
	local->vlen = valueSize;
	local->size = size;
	local->large = NULL;
	
	memcpy(local->key,key,klen);
	if(valueSize > 0 && vsize == 0){
		local->large = (char *)malloc(valueSize);
		if(local->large == NULL)
			return NTdict_ERROR;
		memcpy(local->large,value,valueSize);
	}else{
		memcpy(local->key+ksize,value,valueSize);
	}
	
	page->available -= size;
	page->items += 1;
	page->end = page->end + size;
	return NTdict_OK;
}

char *NTdict_query(NTdict_t *dict,char *key,unsigned int *len)
{
	unsigned int i,j;
	
	unsigned int klen = strlen(key)+1;
	unsigned int hash = NTdict_hash_key(key,klen);
	NTdict_page_t *page = dict->first;
	NTdict_data_t *locate;
	*len = 0;
	for(i=1;i<=dict->pages;i++){
		//printf("page %d items %d\n",i, page->items);
		locate = (NTdict_data_t *)page->d;
		for (j=0;j< page->items;j++){
			//printf("%s %s\n",locate->key,locate->key+locate->ksize);
			if(locate->hash == hash && locate->klen == klen && 0 == memcmp(locate->key,key,locate->klen))
			{
				*len = locate->vlen;
				if(locate->large != NULL)
					return locate->large;
				return locate->key+locate->ksize;
			}
			locate = (NTdict_data_t *)((char *)locate + locate->size);
		}
		page = page->next;
	}
	return NULL;
}

void NTdict_distory(NTdict_t *dict)
{
	if(dict == NULL)
		return;

	NTdict_page_t *page;
	NTdict_data_t *data;
	unsigned int i;
	NTdict_page_t *locate = dict->first;
	//release first page large 
	i=locate->items;
	data=(NTdict_data_t *)locate->d;
	while(i--){
		if(data->large != NULL)
			free(data->large);
		data = (NTdict_data_t *)((char *)data + data->size);
	}
	//release after first page large
	locate = dict->first->next;
	while(locate != NULL){
		page = locate;
		i=page->items;
		data=(NTdict_data_t *)page->d;
		while(i--){
			if(data->large != NULL)
				free(data->large);
			data = (NTdict_data_t *)((char *)data + data->size);
		}
		locate = locate->next;
		free(page);
	}
	free(dict);
}

void NTdict_print(NTdict_t *dict)
{
	unsigned int i,j;
	NTdict_page_t *page = dict->first;
	NTdict_data_t *locate;
	printf("pages %d\n",dict->pages);
	
	for(j=1;j<=dict->pages;j++){
		printf("page %d items %d\n",j, page->items);
		locate = (NTdict_data_t *)page->d;
		for (i=0;i< page->items;i++){
			if(locate->large != NULL)
				printf("%s %s\n",locate->key,locate->large);
			else
				printf("%s %s\n",locate->key,locate->key+locate->ksize);
			locate = (NTdict_data_t *)((char *)locate + locate->size);
		}
		page = page->next;
	}
	
	
}
